﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Tradex.Market {

    /// <summary>
    /// The instrumentPricingItem identifies the allowed prices within a specific price band.
    /// </summary>
    [Serializable ()]
    public class InstrumentPricingItem  {

        /// <summary>
        /// Constructor taking all values.
        /// </summary>
        /// <param name="minimumPrice"></param>
        /// <param name="maximumPrice"></param>
        /// <param name="increment"></param>
        /// <param name="precision"></param>
        public InstrumentPricingItem(
            double minimumPrice, double maximumPrice,
            double increment, byte precision
        ) {
            MinimumPrice = minimumPrice;
            MaximumPrice = maximumPrice;
            Increment = increment;
            Precision = precision;
        }

        /// <summary>
        /// Constructor parsing a string form of the pricing item.
        /// </summary>
        /// <param name="codedPricing"></param>
        public InstrumentPricingItem(string codedPricing) {
            Contract.Assert(codedPricing != null);
            if (codedPricing == null) {
                throw new ArgumentException("stringForm can not be null", "codedPricing");
            }
            Match match = CodedItemRegex.Match(codedPricing);
            string item;

            item = match.Groups[1].Value;
            if (String.IsNullOrEmpty(item)) {
                this.MinimumPrice = Double.NegativeInfinity;
            } else {
                MinimumPrice = Double.Parse(item, CultureInfo.InvariantCulture);
            }

            item = match.Groups[2].Value;
            if (String.IsNullOrEmpty(item)) {
                this.MaximumPrice = Double.PositiveInfinity;
            } else {
                MaximumPrice = Double.Parse(item, CultureInfo.InvariantCulture);
            }

            item = match.Groups[3].Value;
            Increment = Double.Parse(item, CultureInfo.InvariantCulture);

            item = match.Groups[4].Value;
            Precision = Byte.Parse(item, CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// The minimum price the item applies to.
        /// </summary>
        public double MinimumPrice { get; private set; }

        /// <summary>
        /// The maximum price the item applies to.
        /// </summary>
        public double MaximumPrice { get; private set; }

        /// <summary>
        /// The allowed increments within the Minimum and Maximum range.
        /// </summary>
        public double Increment { get; private set; }

        /// <summary>
        /// The precision the price is to be shown.
        /// </summary>
        public byte Precision { get; private set; }

        /// <inheritdoc />
        public override string ToString() {
            int ends = 0;
            if (Double.IsNegativeInfinity(MinimumPrice)) {
                ends = ends | 0x10;
            }
            if (Double.IsPositiveInfinity(MaximumPrice)) {
                ends = ends | 0x01;
            }

            string retval = null;
            string symbolstring = new String('#', Precision);
            string start = (Double.IsNegativeInfinity(MinimumPrice)) ? "" :
                String.Format(CultureInfo.InvariantCulture, "{0:0." + symbolstring + "}", MinimumPrice);
            string end = (Double.IsPositiveInfinity(MaximumPrice)) ? "" :
                String.Format(CultureInfo.InvariantCulture, "{0:0." + symbolstring + "}", MaximumPrice);
            string step = String.Format(CultureInfo.InvariantCulture, "{0:0." + symbolstring + "}", Increment);
            switch (ends) {
                case 0x11:
                    retval = String.Format(
                        CultureInfo.InvariantCulture,
                        "[/]:{0}/{1}",
                        step, Precision
                    );
                    break;
                case 0x01:
                    retval = String.Format(
                        CultureInfo.InvariantCulture,
                        "[{0}/]:{1}/{2}",
                        start, step, Precision
                    );
                    break;
                case 0x10:
                    retval = String.Format(
                        CultureInfo.InvariantCulture,
                        "[/{0}]:{1}/{2}",
                        end, step, Precision
                    );
                    break;
                case 0x00:
                    retval = String.Format(
                        CultureInfo.InvariantCulture,
                        "[{0}/{1}]:{2}/{3}",
                        start, end, step, Precision
                    );
                    break;

            }
            return retval;
        }

        static Regex CodedItemRegex = new Regex(
                @"\[([\.\-0-9]*)/([\.\-0-9]*)\]:([\.\-0-9]*)/([\.\-0-9]*)",
                RegexOptions.CultureInvariant | RegexOptions.Singleline | RegexOptions.Compiled
            );

    }

}
